checksum: implement more traits and functions
authorFelix Krull <f_krull@gmx.de>
Mon, 2 Sep 2019 15:11:35 +0000 (17:11 +0200)
committerColin Walters <walters@verbum.org>
Fri, 6 May 2022 16:53:54 +0000 (12:53 -0400)
rust-bindings/rust/src/checksum.rs

index 2dc250310e3e839189d79f5e6494b60e24d5c605..eee7e5c0975ad86544204663927f754896b334ad 100644 (file)
@@ -1,10 +1,10 @@
-use glib::translate::{from_glib_full, FromGlibPtrFull, ToGlibPtr};
+use glib::translate::{from_glib_full, FromGlibPtrFull, Stash, ToGlibPtr};
 use glib::GString;
-use glib_sys::{g_free, gpointer};
+use glib_sys::{g_free, g_malloc, g_malloc0, gpointer};
 use std::fmt;
+use std::ptr::copy_nonoverlapping;
 
 const BYTES_BUF_SIZE: usize = ostree_sys::OSTREE_SHA256_DIGEST_LEN as usize;
-const HEX_BUF_SIZE: usize = (ostree_sys::OSTREE_SHA256_STRING_LEN + 1) as usize;
 const B64_BUF_SIZE: usize = 44;
 
 /// A binary SHA256 checksum.
@@ -31,7 +31,7 @@ impl Checksum {
     /// Unfortunately, the underlying libostree function has no way to report parsing errors. If the
     /// string is not a valid SHA256 string, the program will abort!
     // TODO: implement by hand to avoid stupid assertions?
-    pub fn from_string(checksum: &str) -> Checksum {
+    pub fn from_hex(checksum: &str) -> Checksum {
         unsafe {
             from_glib_full(ostree_sys::ostree_checksum_to_bytes(
                 checksum.to_glib_none().0,
@@ -39,8 +39,25 @@ impl Checksum {
         }
     }
 
-    /// Return checksum as a hex digest string.
-    fn to_gstring(&self) -> GString {
+    /// Create a `Checksum` from a base64-encoded String.
+    ///
+    /// Data that is too long or too short will be silently accepted. For example, if you pass in
+    /// the empty string, the resulting checksum value will be all 0's.
+    /// // TODO: implement by hand for better error reporting?
+    pub fn from_base64(b64_checksum: &str) -> Checksum {
+        let b64_checksum: Stash<*mut libc::c_char, _> = b64_checksum.to_glib_none();
+        unsafe {
+            let buf = g_malloc0(BYTES_BUF_SIZE) as *mut [u8; BYTES_BUF_SIZE];
+            ostree_sys::ostree_checksum_b64_inplace_to_bytes(
+                b64_checksum.0 as *const [i8; 32],
+                buf as *mut u8,
+            );
+            from_glib_full(buf)
+        }
+    }
+
+    /// Convert checksum to hex-encoded string.
+    pub fn to_hex(&self) -> GString {
         unsafe { from_glib_full(ostree_sys::ostree_checksum_from_bytes(self.bytes)) }
     }
 
@@ -69,6 +86,37 @@ impl Drop for Checksum {
     }
 }
 
+impl Clone for Checksum {
+    fn clone(&self) -> Self {
+        unsafe {
+            let cloned = g_malloc(BYTES_BUF_SIZE) as *mut [u8; BYTES_BUF_SIZE];
+            // copy one array of 32 elements
+            copy_nonoverlapping::<[u8; BYTES_BUF_SIZE]>(self.bytes, cloned, 1);
+            Checksum::new(cloned)
+        }
+    }
+}
+
+impl PartialEq for Checksum {
+    fn eq(&self, other: &Self) -> bool {
+        unsafe {
+            let ret = ostree_sys::ostree_cmp_checksum_bytes(
+                self.bytes as *const u8,
+                other.bytes as *const u8,
+            );
+            ret == 0
+        }
+    }
+}
+
+impl Eq for Checksum {}
+
+impl fmt::Display for Checksum {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{}", self.to_hex())
+    }
+}
+
 impl FromGlibPtrFull<*mut [u8; BYTES_BUF_SIZE]> for Checksum {
     unsafe fn from_glib_full(ptr: *mut [u8; BYTES_BUF_SIZE]) -> Self {
         Checksum::new(ptr)
@@ -87,12 +135,6 @@ impl FromGlibPtrFull<*mut u8> for Checksum {
     }
 }
 
-impl fmt::Display for Checksum {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.to_gstring())
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -100,6 +142,7 @@ mod tests {
 
     const CHECKSUM_STRING: &str =
         "bf875306783efdc5bcab37ea10b6ca4e9b6aea8b94580d0ca94af120565c0e8a";
+    const CHECKSUM_BASE64: &str = "v4dTBng+_cW8qzfqELbKTptq6ouUWA0MqUrxIFZcDoo";
 
     #[test]
     fn should_create_checksum_from_bytes() {
@@ -110,16 +153,44 @@ mod tests {
 
     #[test]
     fn should_parse_checksum_string_to_bytes() {
-        let csum = Checksum::from_string(CHECKSUM_STRING);
+        let csum = Checksum::from_hex(CHECKSUM_STRING);
         assert_eq!(csum.to_string(), CHECKSUM_STRING);
     }
 
     #[test]
     fn should_convert_checksum_to_base64() {
-        let csum = Checksum::from_string(CHECKSUM_STRING);
-        assert_eq!(
-            csum.to_base64(),
-            "v4dTBng+_cW8qzfqELbKTptq6ouUWA0MqUrxIFZcDoo"
-        );
+        let csum = Checksum::from_hex(CHECKSUM_STRING);
+        assert_eq!(csum.to_base64(), CHECKSUM_BASE64);
+    }
+
+    #[test]
+    fn should_convert_base64_string_to_checksum() {
+        let csum = Checksum::from_base64(CHECKSUM_BASE64);
+        assert_eq!(csum.to_base64(), CHECKSUM_BASE64);
+        assert_eq!(csum.to_string(), CHECKSUM_STRING);
+    }
+
+    #[test]
+    fn should_be_zeros_for_empty_base64_string() {
+        let csum = Checksum::from_base64("");
+        assert_eq!(csum.to_string(), "00".repeat(BYTES_BUF_SIZE));
+    }
+
+    #[test]
+    fn should_compare_checksums() {
+        let csum = Checksum::from_hex(CHECKSUM_STRING);
+        assert_eq!(csum, csum);
+        let csum2 = Checksum::from_hex(CHECKSUM_STRING);
+        assert_eq!(csum2, csum);
+    }
+
+    #[test]
+    fn should_clone_value() {
+        let csum = Checksum::from_hex(CHECKSUM_STRING);
+        let csum2 = csum.clone();
+        assert_eq!(csum2, csum);
+        let csum3 = csum2.clone();
+        assert_eq!(csum3, csum);
+        assert_eq!(csum3, csum2);
     }
 }